package com.ikkong.qy.util;

import java.io.File;
import java.io.StringReader;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;

import com.csvreader.CsvWriter;
import com.ikkong.biz.model.AsyncResult;
import com.ikkong.biz.model.Classes;
import com.ikkong.biz.model.Flow;
import com.ikkong.biz.model.FlowSegment;
import com.ikkong.biz.model.Notice;
import com.ikkong.biz.model.Parent;
import com.ikkong.biz.model.Teacher;
import com.ikkong.biz.model.WeixinUser;
import com.ikkong.core.constant.Cst;
import com.ikkong.core.dao.Blade;
import com.ikkong.core.dao.Db;
import com.ikkong.core.jfinal.ext.kit.JStrKit;
import com.ikkong.system.model.Dept;
import com.jfinal.core.Controller;
import com.jfinal.kit.HttpKit;
import com.jfinal.kit.PropKit;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;

public class WeixinApi {

	public static String CORP_ID = null;
	private static String SECRET_MANAGER = null;
	private static String SECRET_CHAT = null;

	private static String AGENT_ID_NOTICE_TEACHER = null;
	private static String AGENT_ID_NOTICE_PARENTS = null;
	private static String AGENT_ID_FLOW = null;
	
	
	private static String TAG_TEACHER = null;
	private static String TAG_PARENT = null;

	private static TokenManager manager = null;

	private static TokenManager chatManager =null;
	
	private static WeixinTicketManager ticketManager = new WeixinTicketManager();
	private static WXBizMsgCrypt bizMsgCrypt;

	public static void init(){
		CORP_ID = PropKit.get("weixin.corpId");
		SECRET_MANAGER = PropKit.get("weixin.secret_manager");
		SECRET_CHAT = PropKit.get("weixin.secret_chat");
		
		AGENT_ID_NOTICE_TEACHER = PropKit.get("weixin.agent_id_notice_teacher");
		AGENT_ID_NOTICE_PARENTS = PropKit.get("weixin.agent_id_notice_parent");
		AGENT_ID_FLOW = PropKit.get("weixin.agent_id_flow");
		
		TAG_TEACHER = PropKit.get("weixin.tag_teacher");
		TAG_PARENT = PropKit.get("weixin.tag_parent");
		
		manager = new TokenManager(CORP_ID, SECRET_MANAGER);
		chatManager = new TokenManager(CORP_ID, SECRET_CHAT);
		try {
			bizMsgCrypt = new WXBizMsgCrypt(PropKit.get("weixin.token"), PropKit.get("weixin.EncodingAESKey"), CORP_ID);
		} catch (AesException e) {
			e.printStackTrace();
		}
	}
	
	
	
	/**
	 * 创建班级群聊
	 * 
	 * @param classId
	 */
	public static void createClassChat(Integer classId) {
		Classes classes = Blade.create(Classes.class).findById(classId);
		String pChatId = classes.getParent_chat_id();
		String sChatId = classes.getStu_chat_id();

		String headTeacherId = "";
		String teacherIds = "";

		headTeacherId = Db.init().queryStr(
				"select ifnull(t.mobile,'') from tb_teacher t,tb_classes c where c.id = " + classId
						+ " and c.head_teacher = t.id", null);
		teacherIds = Db.init().queryStr(
				"select ifnull(group_concat(t.mobile),'') from tb_teacher t,tb_classes c where c.id = " + classId
						+ " and (c.head_teacher = t.id or c.teachers like concat('%,',t.id,',%'))", null);
		teacherIds = teacherIds.replaceAll(",", "\",\"");

		StringBuilder sb = null;
		String url = null;
		if (JStrKit.isBlank(sChatId)) {
			String stuChatId = createClassChatId(classId, 3);
			sb = new StringBuilder();

			String stuIds = Db.init().queryStr(
					"select ifnull(group_concat(s.mobile),'') from tb_student s where s.class_id = " + classId, null);
			stuIds = stuIds.replaceAll(",", "\",\"");
			sb.append("{\"chatid\": \"");
			sb.append(stuChatId);
			sb.append("\",\"name\": \"");
			sb.append(CommonUtils.getClassName(classes));
			sb.append("学生群\",\"owner\": \"");
			sb.append(headTeacherId);
			sb.append("\",\"userlist\":[\"");
			sb.append(teacherIds);
			sb.append("\"");
			sb.append(stuIds);
			sb.append("\"]}");
			url = "https://qyapi.weixin.qq.com/cgi-bin/chat/create?access_token=" + chatManager.getEnableToken();
			String str = HttpKit.post(url, sb.toString());
			System.out.println("sChat result:" + str);
			classes.setStu_chat_id(stuChatId);
			classes.setVersion(classes.getVersion() + 1);
			Blade.create(Classes.class).update(classes);
		}

		if (JStrKit.isBlank(pChatId)) {
			String parChatId = createClassChatId(classId, 2);
			sb = new StringBuilder();

			String stuIds = Db.init().queryStr(
					"select ifnull(group_concat(p.mobile),'') from tb_parent p where p.class_id = " + classId, null);
			stuIds = stuIds.replaceAll(",", "\",\"");
			sb.append("{\"chatid\": \"");
			sb.append(parChatId);
			sb.append("\",\"name\": \"");
			sb.append(CommonUtils.getClassName(classes));
			sb.append("家长群\",\"owner\": \"");
			sb.append(headTeacherId);
			sb.append("\",\"userlist\":[\"");
			sb.append(teacherIds);
			sb.append("\"");
			sb.append(stuIds);
			sb.append("\"]}");
			url = "https://qyapi.weixin.qq.com/cgi-bin/chat/create?access_token=" + chatManager.getEnableToken();
			String str = HttpKit.post(url, sb.toString());
			System.out.println("pChat result:" + str);
			classes.setParent_chat_id(parChatId);
			classes.setVersion(classes.getVersion() + 1);
			Blade.create(Classes.class).update(classes);
		}
	}

	/**
	 * @see getWxUserId
	 */
	public static void syncData() {
		Blade dao = Blade.create(AsyncResult.class);
		AsyncResult result = dao.findFirst("select * from tb_async_result ar where ar.type='contact'", null);
		if (result.getStatus() == 1) {
			return;
		}
		
		String des = "";
		
		result.setStatus(1);
		result.setStart_time(new Date());
		result.setVersion(result.getVersion() + 1);
		dao.update(result);
		CsvWriter writer = null;
		File folder = new File(Cst.me().getRealPath() + "/sync");
		
		if (!folder.exists()) {
			folder.mkdirs();
		}
		System.out.println("目录地址："+folder.getAbsolutePath()+" exist?"+folder.exists());
		List<Dept> deptList = Blade.create(Dept.class).findAll();
		try {
			writer = new CsvWriter(Cst.me().getRealPath() + "/sync/info.csv", ',', Charset.forName("GBK"));
			String[] contents = { "部门名称", "部门ID", "父部门ID" };
			writer.writeRecord(contents);
			for (int i = 0; i < deptList.size(); i++) {
				Dept dept = deptList.get(i);
				int pid = dept.getPid();
				contents = new String[] { dept.getFullname(), String.valueOf(dept.getId()), String.valueOf(pid) };
				writer.writeRecord(contents);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (writer != null) {
				writer.close();
			}
		}

		File file = new File(Cst.me().getRealPath() + "/sync/info.csv");
		String token = manager.getEnableToken();
		String res = CommonUtils.uploadMediaFile("https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token="
				+ token + "&type=file", file, null);
		Map<String, Object> resultMap = CommonUtils.getJsonMap(res);
		CommonUtils.tPrint(resultMap, "media 1");
		des = "dept file:"+res;
		result.setDes(des);
		result.setVersion(result.getVersion() + 1);
		dao.update(result);
		String url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceparty?access_token=" + manager.getEnableToken();
		System.out.println("部门同步url:" + url);
		String data = "{\"media_id\":\"" + resultMap.get("media_id") + "\"}";
		System.out.println("部门同步data:" + data);
		res = HttpKit.post(url, data);
		System.out.println("部门更新:" + res);
		

		des =des+ " dept sync:"+res;
		result.setDes(des);
		result.setVersion(result.getVersion() + 1);
		dao.update(result);
		
		// 开始导入用户
		List<Map> userList = Db
				.init()
				.queryListMap(
						"select v.*, concat(ifnull(group_concat(c.stu_dept_id),''),',', ifnull(group_concat(c.parent_dept_id),'')) cd_id"
								+ " from v_weixin_users v left join tb_classes c on (v.type = 1 and (c.head_teacher = v.id or c.teachers like concat('%,',v.id,',%'))) where v.mobile is not null and v.mobile != '' "
								+ "group by v.mobile");
		if (userList != null && userList.size() > 0) {

			try {
				try {

					writer = new CsvWriter(Cst.me().getRealPath() + "/sync/info2.csv", ',', Charset.forName("GBK"));
					String[] contents = { "姓名", "账号", "微信号", "手机号", "邮箱", "所在部门", "职位" };
					writer.writeRecord(contents);
					for (int i = 0; i < userList.size(); i++) {
						Map<String, Object> user = userList.get(i);
						String mobile = JStrKit.valueOf(user.get("mobile"));
						String name = JStrKit.valueOf(user.get("name"));
						String dept = JStrKit.valueOf(user.get("dept"));
						String type = JStrKit.valueOf(user.get("type"));
						if ("1".equals(type)) {
							dept = JStrKit.removeWrapWithDelimiter(dept);
							String cd_id = JStrKit.valueOf(user.get("cd_id"));
							if (cd_id.length() > 1) {
								dept = dept + "," + cd_id;
							}
						}
						dept = dept.replaceAll(",", ";");
						String position = JStrKit.valueOf(user.get("position"));

						contents = new String[] { name, mobile, "", mobile, "", dept, position };
						writer.writeRecord(contents);
					}
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException();
				} finally {
					if (writer != null) {
						writer.close();
					}
				}

				file = new File(Cst.me().getRealPath() + "/sync/info2.csv");
				res = CommonUtils.uploadMediaFile("https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token="
						+ manager.getEnableToken() + "&type=file", file, null);
				resultMap = CommonUtils.getJsonMap(res);
				CommonUtils.tPrint(resultMap, "media 2");

				des =des+ " user file:"+res;
				result.setDes(des);
				result.setVersion(result.getVersion() + 1);
				dao.update(result);
				
				url = "https://qyapi.weixin.qq.com/cgi-bin/batch/replaceuser?access_token=" + manager.getEnableToken();
				System.out.println("用户同步url:" + url);
				data = "{\"media_id\":\"" + resultMap.get("media_id") + "\"}";
				res = HttpKit.post(url, data);
				System.out.println("用户同步:" + res);


				des =des+ " user sync:"+res;
				result.setDes(des);
				result.setVersion(result.getVersion() + 1);
				dao.update(result);
				
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
			}
		}

		// 处理标签
		url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers?access_token=" + manager.getEnableToken();
		String teacherIds = Db.init().queryStr("select group_concat(v.mobile) from v_weixin_users v where v.type = 1",
				null);
		teacherIds = teacherIds.replaceAll(",", "\",\"");
		data = "{\"tagid\": \""+TAG_TEACHER+"\",\"userlist\":[ \"" + teacherIds + "\"]}";
		System.out.println("教师标签同步url:" + url);
		System.out.println("教师标签同步data:" + data);
		res = HttpKit.post(url, data);
		System.out.println("教师标签同步:" + res);		

		des =des+ " teacher tag:"+res;
		result.setDes(des);
		result.setVersion(result.getVersion() + 1);
		dao.update(result);

		// 处理标签
		url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers?access_token=" + manager.getEnableToken();
		String parentIds = Db.init().queryStr(
				"select group_concat(v.mobile) from v_weixin_users v  where v.type in (2,3)", null);
		parentIds = parentIds.replaceAll(",", "\",\"");
		data = "{\"tagid\": \""+TAG_PARENT+"\",\"userlist\":[ \"" + parentIds + "\"]}";
		System.out.println("家长标签同步url:" + url);
		System.out.println("家长标签同步data:" + data);
		res = HttpKit.post(url, data);
		System.out.println("家长标签同步:" + res);

		des =des+ " parent tag:"+res;
		result.setDes(des);
		result.setVersion(result.getVersion() + 1);
		dao.update(result);
		
		result.setStatus(2);
		result.setFinish_time(new Date());
		result.setVersion(result.getVersion() + 1);
		dao.update(result);
	}

	public static String getWeixinUserIdByCode(String code) {
		String token = manager.getEnableToken();
		String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=" + token + "&code=" + code;
		String resp = HttpKit.get(url, null);
		Map<String, Object> resultMap = CommonUtils.getJsonMap(resp);
		CommonUtils.tPrint(resultMap, "user");

		return resultMap.getOrDefault("UserId", "").toString();
	}

	/**
	 * 
	 * @see syncData
	 * @param user
	 * @return
	 */
	public static String getWxUserId(WeixinUser user) {
		if (user instanceof Teacher) {
			return "t_" + user.getId();

		} else if (user instanceof Parent) {
			return "p_" + user.getId();

		} else {
			return "s_" + user.getId();
		}
	}

	/**
	 * 
	 * @param classId
	 *            班级ID
	 * @param type
	 *            2-家长，3-学生
	 * @return
	 */
	public static String createClassChatId(Integer classId, int type) {
		if (type == 2) {
			return "cp" + classId + "t" + System.currentTimeMillis();
		} else {
			return "cs" + classId + "t" + System.currentTimeMillis();
		}
	}
	
	/**
	 * 推送流程变更
	 * @param flow
	 * @param prevSegment		上一环节。如果是新发起流程，该参数为null
	 * @param nextSegment		当前环节。如果流程结束，该参数为null
	 */
	public static void pushFlow(Flow flow, FlowSegment prevSegment, FlowSegment nextSegment){
		new Thread(){		//避免线程堵塞，采用异步处理
			public void run() {
				Teacher sender = Blade.create(Teacher.class).findById(flow.getCuser());
				String preUser = "";
				String nextUser = "";
				
				if(prevSegment != null){
					preUser = prevSegment.getOperator();
				}
				if(nextSegment != null){
					nextUser = nextSegment.getOperator();
				}
				
				String title = "流程变更通知";
				String des = "";
				if(prevSegment==null){
					des =  "您发起了一个新流程《"+flow.getTitle()+"》,下一环节处理人为（"+nextUser+"）";							
				}else if(nextSegment==null){
					des =  "您的流程《"+flow.getTitle()+"》已由用户（"+preUser+"）处理完毕，该流程已结束";									
				}else{
					des =  "您的流程《"+flow.getTitle()+"》已由用户（"+preUser+"）处理完毕，下一环节处理人为（"+nextUser+"）";				
					
				}				
				{
				String[] result = WeixinInterface.pushNews(getEnableToken(), AGENT_ID_FLOW,title, des, null, sender.getMobile(), null, createViewFlowUrl(flow.getId()));
				System.out.println("url1:"+result[0]);
				System.out.println("data1:"+result[1]);
				System.out.println("res1:"+result[2]);
				}
				
				if(nextSegment != null){
					Teacher receiver = Blade.create(Teacher.class).findById(nextSegment.getOperator_id());
					title = "您有新的待处理流程";
					des = sender.getName()+"发起的流程《"+flow.getTitle()+"》等待您的处理";
					String[] result = WeixinInterface.pushNews(getEnableToken(), AGENT_ID_FLOW,title, des, null, receiver.getMobile(), null, createViewFlowUrl(flow.getId()));
					System.out.println("url1:"+result[0]);
					System.out.println("data1:"+result[1]);
					System.out.println("res1:"+result[2]);
				}
			}
		}.start();
	}

	/**
	 * 推送通知
	 * @param notice
	 */
	public static void pushNotice(Notice notice) {		
		String teacherIds = notice.getTeacher_auth();
		if(!JStrKit.isBlank(teacherIds)){
			String userMobiles = Db.init().queryStr(
					"select group_concat(t.mobile) from tb_teacher t where t.id in (" + teacherIds + ")", null);
			if (!JStrKit.isBlank(userMobiles)) {
				userMobiles = userMobiles.replaceAll(",", "|");
				WeixinInterface.pushNews(getEnableToken(), AGENT_ID_NOTICE_TEACHER, notice.getTitle(), null, null, userMobiles, null, createViewNoticeUrl(notice.getId()));
			}
		}

		String parentDepts = notice.getParent_auth();
		if("null".equalsIgnoreCase(parentDepts)){
			parentDepts = "";
		}
		String studentDepts = notice.getStudent_auth();
		if("null".equalsIgnoreCase(studentDepts)){
			studentDepts = "";
		}
		StringBuilder sb = new StringBuilder();
		String[] array = parentDepts.split(",");
		for (int i = 0; i < array.length; i++) {
			if(!JStrKit.isBlank(array[i])){
				sb.append(array[i]);
				sb.append("|");
			}
		}
		
		array = studentDepts.split(",");
		for (int i = 0; i < array.length; i++) {
			if(!JStrKit.isBlank(array[i])){
				sb.append(array[i]);
				sb.append("|");
			}
		}
		
		if(sb.length() > 1){
			sb.setLength(sb.length()-1);
			WeixinInterface.pushNews(getEnableToken(), AGENT_ID_NOTICE_TEACHER, notice.getTitle(), null, null, null, sb.toString(), createViewNoticeUrl(notice.getId()));
		}
	}

	public static String createViewNoticeUrl(Integer noticeId) {
		StringBuilder sb = new StringBuilder();
		sb.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
		sb.append("appid=");
		sb.append(CORP_ID);
		
		String url = Cst.me().getBasePath()+"/weixinInter/route";
		url = URLEncoder.encode(url);
		
		sb.append("&redirect_uri="+url);
		sb.append("&response_type=code");
		sb.append("&scope=SCOPE");
		sb.append("&state=");
		sb.append("noticeview_" + noticeId);
		sb.append("#wechat_redirect");

		return sb.toString();
	}
	
	public static String createViewFlowUrl(Integer flowId){
		StringBuilder sb = new StringBuilder();
		sb.append("https://open.weixin.qq.com/connect/oauth2/authorize?");
		sb.append("appid=");
		sb.append(CORP_ID);
		
		String url = Cst.me().getBasePath()+"/weixinInter/route";
		url = URLEncoder.encode(url);
		
		sb.append("&redirect_uri="+url);
		sb.append("&response_type=code");
		sb.append("&scope=SCOPE");
		sb.append("&state=");
		sb.append("flowview_" + flowId);
		sb.append("#wechat_redirect");

		return sb.toString();
	}
	
	public static String getEnableChatToken(){
		return chatManager.getEnableToken();
	}
	
	public static String getEnableToken(){
		return manager.getEnableToken();
	}
	
	public static void createQyJsToken(Controller controller){
		String ticket = ticketManager.getEnableTicket(manager.getEnableToken());
		createJsToken(controller, ticket);
	}
	
	public static void createQyChatJsToken(Controller controller){
		String ticket = ticketManager.getEnableTicket(chatManager.getEnableToken());
		createJsToken(controller, ticket);
	}
	
	public static void createJsToken(Controller controller, String ticket){
		StringBuffer url = controller.getRequest().getRequestURL();
		String params = controller.getRequest().getQueryString();
		if(!JStrKit.isBlank(params)){
			url.append("?");
			url.append(params);
		}
		
		String noncestr = "xiaoxuntong";
		long timeStamp = System.currentTimeMillis()/1000l;
		String text = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timeStamp+"&url="+url.toString();
		System.out.println("ori:"+text);
		String signature = com.ikkong.qy.util.Sha1.SHA1Digest(text);
		System.out.println("signature:"+signature);
		if(signature.length() < 40){
			int length = signature.length();
			for(int i = length;i<40;i++){
				signature = "0"+signature;
			}
		}
		controller.setAttr("ori",text);
		controller.setAttr("appId",WeixinApi.CORP_ID);
		controller.setAttr("timestamp", timeStamp);
		controller.setAttr("nonceStr", noncestr);
		controller.setAttr("signature", signature);
	}
	
	public static WXBizMsgCrypt getWxBizMsgCrypt(){
		if(bizMsgCrypt == null){
			try {
				bizMsgCrypt = new WXBizMsgCrypt(PropKit.get("weixin.token"), PropKit.get("weixin.EncodingAESKey"), CORP_ID);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return bizMsgCrypt;
	}
	
	public static Map<String, String> parseXml(String xmltext){
		Map<String, String> map = new HashMap<String, String>();		
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			StringReader sr = new StringReader(xmltext);
			InputSource is = new InputSource(sr);
			Document document = db.parse(is);
			Element root = document.getDocumentElement();
			
			String userId = root.getElementsByTagName("FromUserName").item(0).getTextContent();
			map.put("FromUserName", userId);
			
			String msgType =  root.getElementsByTagName("MsgType").item(0).getTextContent();
			map.put("MsgType", msgType);
			
			if("image".equals(msgType)||"video".equals(msgType)||"shortvideo".equals(msgType)){
				String mediaId = root.getElementsByTagName("MediaId").item(0). getTextContent();
				map.put("MediaId", mediaId);
			}
			if("video".equals(msgType)||"shortvideo".equals(msgType)){
				String mediaId = root.getElementsByTagName("ThumbMediaId").item(0). getTextContent();
				map.put("ThumbMediaId", mediaId);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return map;
	}
}
